import numpy as np
import random
import math

def cnmf(X, C, S, landa, r, k):
    '''
    X是原始矩阵，维度为d*n
    C是标签知识矩阵，只针对前l个有标签的样本，维度为l*c（l——有标签样本数量，c——类别数量）
    S是标签指示矩阵，是对角矩阵，
    landa是正则化参数，0.001，0.01，0.1，1，10，100，1000
    r是分解的两个非负矩阵的隐变量维度，要远小于原始矩阵的维度
    k是迭代次数

    input X,Y
    output U,Z,F
    '''
    d, n = X.shape
    l, c = C.shape

    U = np.mat(np.random.rand(d, r))
    Z = np.mat(np.random.rand(c, r))
    F = np.mat(np.random.rand(n, c))

    #求Y
    Y = np.zeros((n, c ))
    for i in range(l):
        for j in range(c):
            Y[i, j] = C[i, j]

    #求W,这里把wij的一个系数写成了1
    t = 1
    W = np.zeros((n, n ))
    for i_w in range(n):
        for j_w in range(n):
            if i_w != j_w:
                fan = np.linalg.norm(X.T[i_w] - X.T[j_w])
                #print(math.pow(fan, 2))
                W[i_w, j_w] = math.exp(- (math.pow(fan, 2))/(2* math.pow(t, 2)))
    #print(W)

    #求出D，计算wj，即W的每一列之和
    D = np.zeros((n, n))
    for i_d in range(n):
        D[i_d, i_d] = sum(W.T[i_d])
    #print(D)




    for x in range(k):
        print('---------------------------------------------------')
        print('开始第', x, '轮迭代')

        #update U
        a_u = U * Z.T * F.T * F * Z
        b_u = X * F * Z
        for i_1 in range(d):
            for j_1 in range(r):
                if a_u[i_1, j_1] != 0:
                    U[i_1, j_1] = U[i_1, j_1] * b_u[i_1, j_1] / a_u[i_1, j_1]
        #print(U)

        #update Z
        #print(Z.shape,n,r)
        a_z = F.T * F * Z * U.T * U
        b_z = F.T* X.T * U
        for i_2 in range(c):
            for j_2 in range(r):
                #print(i_2, j_2, a_z[i_2,j_2])
                if a_z[i_2,j_2] != 0:
                    Z[i_2,j_2] = Z[i_2,j_2] * b_z[i_2,j_2] / a_z[i_2,j_2]

        # update
        #print( landa  ,type(S))
        a_f = F * Z * U.T * U * Z.T + landa * D * F +landa * S * F
        b_f = X.T * U * Z.T +landa * W * F +landa * S * Y
        for i_3 in range(n ):
            for j_3 in range(c):
                if a_f[i_3, j_3] != 0:
                    F[i_3, j_3] = F[i_3, j_3] * b_f[i_3, j_3] / a_f[i_3, j_3]
        print('第', x, '轮迭代结束')


    return U, Z , F

if __name__ == "__main__":
    X = [[5, 3, 2, 1, 2, 3],
         [4, 2, 2, 1, 1, 5],
         [1, 1, 2, 5, 2, 3],
         [1, 2, 2, 4, 3, 2],
         [2, 1, 5, 4, 1, 1],
         [1, 2, 2, 5, 3, 2],
         [2, 5, 3, 2, 2, 5],
         [2, 1, 2, 5, 1, 1],]#8*6,6个样本
    X = np.mat(X)
   # print(X.T[0])
    C = [[0, 0, 1],
         [0, 1, 0],
         [0, 1, 0],
         [1, 0, 0], ]  # 4*3，假设有4个样本有标签，总共有三类标签
    #print(X)
    C = np.mat(C)
    S = [[0, 0, 0, 0, 0, 0],
         [0, 1, 0, 0, 0, 0],
         [0, 0, 1, 0, 0, 0],
         [0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 1, 0],
         [0, 0, 0, 0, 0, 1]]
    S = np.mat(S)
    landa = 0.1
    U, Z , F = cnmf(X, C, S, landa, 2, 100)
    print(U.shape, Z.shape, F.shape)
    V = F * Z
    print(U * V.T)